﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace net.xBei.Helper;
/// <summary>
/// <see cref="AutoMapper.IMapper"/>
/// </summary>
public static class AutoMapHelper {
    /// <summary>
    /// 自动映射
    /// </summary>
    /// <typeparam name="TDestination"></typeparam>
    /// <param name="source"></param>
    /// <param name="mapper"></param>
    /// <returns></returns>
    public static TDestination AutoMapping<TDestination>(this object source, AutoMapper.IMapper mapper)
        => mapper.Map<TDestination>(source);
    /// <summary>
    /// 自动映射
    /// </summary>
    /// <typeparam name="TDestination"></typeparam>
    /// <param name="source"></param>
    /// <param name="mapper"></param>
    /// <returns></returns>
    public static async Task<TDestination> AutoMappingAsync<TDestination>(this Task<object> source, AutoMapper.IMapper mapper)
        => mapper.Map<TDestination>(await source);
    /// <summary>
    /// 自动映射
    /// </summary>
    /// <typeparam name="TDestination"></typeparam>
    /// <param name="source"></param>
    /// <param name="mapper"></param>
    /// <param name="afterMap">映射已经调用</param>
    /// <returns></returns>
    public static TDestination AutoMapping<TDestination>(this object source, AutoMapper.IMapper mapper, Action<TDestination>? afterMap = null) {
        var d = mapper.Map<TDestination>(source);
        afterMap?.Invoke(d);
        return d;
    }
    /// <summary>
    /// 自动映射
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TDestination"></typeparam>
    /// <param name="source"></param>
    /// <param name="mapper"></param>
    /// <returns></returns>
    public static async Task<TDestination> AutoMappingAsync<TSource, TDestination>(this Task<TSource> source, AutoMapper.IMapper mapper)
        => mapper.Map<TSource, TDestination>(await source);
    /// <summary>
    /// 自动映射
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TDestination"></typeparam>
    /// <param name="source"></param>
    /// <param name="mapper"></param>
    /// <returns></returns>
    public static TDestination AutoMapping<TSource, TDestination>(this TSource source, AutoMapper.IMapper mapper)
        => mapper.Map<TSource, TDestination>(source);
    /// <summary>
    /// 自动映射
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TDestination"></typeparam>
    /// <param name="source"></param>
    /// <param name="mapper"></param>
    /// <param name="afterMap">映射已经调用</param>
    /// <returns></returns>
    public static TDestination AutoMapping<TSource, TDestination>(this TSource source,
                                                                  AutoMapper.IMapper mapper,
                                                                  Action<TDestination>? afterMap = null) {
        var d = mapper.Map<TDestination>(source);
        afterMap?.Invoke(d);
        return d;
    }
    #region List
    /// <summary>
    /// 自动映射（源和处理方法都是同步）
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TDestination"></typeparam>
    /// <param name="source"></param>
    /// <param name="mapper"></param>
    /// <param name="afterMap"></param>
    /// <returns></returns>
    public static TDestination[] AutoMappingList<TSource, TDestination>(this IEnumerable<TSource> source,
                                                                        AutoMapper.IMapper mapper,
                                                                        Action<TSource, TDestination>? afterMap = default) {
        return afterMap == default
            ? source.Select(i => mapper.Map<TDestination>(i)).ToArray()
            : source.Select(i => {
                var d = mapper.Map<TDestination>(i);
                afterMap.Invoke(i, d);
                return d;
            }).ToArray();
    }
    /// <summary>
    /// 自动映射（源是异步，没有处理方法）
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TDestination"></typeparam>
    /// <param name="source"></param>
    /// <param name="mapper"></param>
    /// <returns></returns>
    public static async Task<TDestination[]> AutoMappingListAsync<TSource, TDestination>(this Task<TSource[]> source,
                                                                                         AutoMapper.IMapper mapper) {
        return (await source).Select(i => mapper.Map<TDestination>(i)).ToArray();
    }
    /// <summary>
    /// 自动映射（源是同步，但是处理方法是异步）
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TDestination"></typeparam>
    /// <param name="source"></param>
    /// <param name="mapper"></param>
    /// <param name="afterMapAsync"></param>
    /// <returns></returns>
    public static async Task<TDestination[]> AutoMappingListAsync<TSource, TDestination>(this TSource[] source,
                                                                        AutoMapper.IMapper mapper,
                                                                        Func<TSource, TDestination, Task> afterMapAsync) {
        return await Task.WhenAll(source.Select(async i => {
            var d = mapper.Map<TDestination>(i);
            await afterMapAsync.Invoke(i, d);
            return d;
        }));
    }
    /// <summary>
    /// 自动映射（源是异步，处理方法是同步）
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TDestination"></typeparam>
    /// <param name="source"></param>
    /// <param name="mapper"></param>
    /// <param name="afterMap"></param>
    /// <returns></returns>
    public static async Task<TDestination[]> AutoMappingListAsync<TSource, TDestination>(this Task<TSource[]> source,
                                                                                         AutoMapper.IMapper mapper,
                                                                                         Action<TSource, TDestination> afterMap) {
        return (await source).Select(i => {
            var d = mapper.Map<TDestination>(i);
            afterMap.Invoke(i, d);
            return d;
        }).ToArray();
    }
    /// <summary>
    /// 自动映射（源和处理方法都是异步）
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TDestination"></typeparam>
    /// <param name="source"></param>
    /// <param name="mapper"></param>
    /// <param name="afterMapAsync"></param>
    /// <returns></returns>
    public static async Task<TDestination[]> AutoMappingListAsync<TSource, TDestination>(this Task<TSource[]> source,
                                                                                         AutoMapper.IMapper mapper,
                                                                                         Func<TSource, TDestination, Task> afterMapAsync) {
        return await Task.WhenAll((await source).Select(async i => {
            var d = mapper.Map<TDestination>(i);
            await afterMapAsync(i, d);
            return d;
        }));
    }
    #endregion
}
